#include "DB.h"
#include "DBPageManager.h"
#include "DBIndexManager.h"
#include "DBError.h"
#include <Windows.h>
#include <process.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h> 
#include <sys\stat.h>


int insertNormal(const char* tableName, colValue* valueArr)
{
    //printf("In insertNormal.\n");

    DB_PAGE* buf = NULL;
    char* dataBuf;
    int pageid;
    int fileid;
    int newpageid;
    int error;
    int i = 0;
    int recordSize = 0;
    char* tName = malloc(100);
    // reccord how many vchars
    int vcharNumber = 0;
    strcpy(tName, tableName);


    char fileName[100];
    strcpy(fileName, tableName);
    col* colDef = malloc(sizeof(col));
    strcat(fileName, ".dbf");

    // open table definition file
    FILE* fp;
    fp = fopen(fileName, "rb+");
    if (fp == NULL)
    {
        printf("can not find file.\n");
        return -1;
    }

    // get the colCount(how many cols are defined in the table)
    unsigned long recordCount;
    int colCount;
    fread(&recordCount, sizeof(unsigned long), 1, fp);
    //printf("the recordCount is : %d.\n", recordCount);
    fread(&colCount, sizeof(int), 1, fp);
    for (i = 0; i < colCount; i++)
    {
        fread(colDef, sizeof(col), 1, fp);
        if (colDef->type == DATA_VCHAR)
        {
            vcharNumber = vcharNumber + 1;
        }
        recordSize = recordSize + colDef->size;
    }
    recordSize = recordSize + sizeof(unsigned long) + vcharNumber * sizeof(int) + colCount * sizeof(char);
    fseek(fp, sizeof(unsigned long) + sizeof(int), 0);


    // init DBFile
    fileid = DBFileIsOpen(tName);
    if (fileid == -1)
    {
        fileid = DBOpenFile(tName);
        //printf("fileid is %d.\n", fileid);
        if (fileid < 0)
        {
            printf("error in DBFileOpen!\n");
            DBPrintError(fileid);
            return -1;
        }
    } 

    // get a page
    if ( (error = DBGetFirstPage(fileid, &newpageid, &buf)) != DB_OK )
    {
        printf("error in GetFirstPage!\n");
        DBPrintError(error);
        return -1;
    }


    //printf("the page fetched is : %d.\n", newpageid);
    //printf("the slot count of the page is %d.\n", buf->pgheader.slotCnt);
    //printf("and the remaining space is : %d.\n", DB_PGSIZE - buf->pgheader.slotCnt * recordSize);


    // if the page is too small, find one that is big enough
    while (DB_PGSIZE - buf->pgheader.slotCnt * recordSize < recordSize)
    {
        // set the pageid
        pageid = newpageid;
        //printf("look for the next page of page %d.\n", pageid);
        //free(buf);
        error = DBGetNextPage(fileid, pageid, &newpageid, &buf);
        DBPageFix(fileid, pageid);
        if (error < 0)
        {
            DBPrintError(error);
            printf("look for page error!\n");
            break;
        }
        else
        {
            //printf("the page fetched is : %d.\n", newpageid);
            //printf("the slot count of the page is %d.\n", buf->pgheader.slotCnt);
            //printf("and the remaining space is : %d.\n", DB_PGSIZE - buf->pgheader.slotCnt * recordSize);
        }
    }


    // can not find a page big enough then allocate
    if (error == DB_ERROR_EOF)
    {
        //printf("allocate a new page.\n");
        //free(buf);
        error = DBAllocPage(fileid, &newpageid, &buf);
        //printf("allocate a new page : %d.\n", newpageid);
        if (error < 0)
        {
            DBPrintError(error);
        }   
        buf->pgheader.slotCnt = 0;
    }


    //printf("The final pageid is : %d.\n", newpageid);
    //printf("the slot count of the page is %d.\n", buf->pgheader.slotCnt);
    //printf("and the remaining space is : %d.\n", DB_PGSIZE - buf->pgheader.slotCnt * recordSize);

    DBPageUsed(fileid, newpageid);

    // now we have a page big enough to write a record
    dataBuf = buf->pgdata;
    dataBuf = dataBuf + buf->pgheader.slotCnt * recordSize;


    // insert the recoreds
    //printf("begin to write.\n");
    // write to buffer page the record number of this record
    memcpy(dataBuf, &recordCount, sizeof(unsigned long));
    dataBuf = dataBuf + sizeof(unsigned long);
    for (i = 0; i < colCount; i++, valueArr++)    
    {
        fread(colDef, sizeof(col), 1, fp);

        /*
           printf("----------------------------basic info-------------------------------\n");   
           printf("col name is : %s.\n", colDef->name);
           printf("col size of : %d.\n", colDef->size);
           printf("col type is : %d.\n", colDef->type);
           if (valueArr->isChar == 0)
           {
           printf("char value is : %s.\n", valueArr->value.charValue);
           }
           else
           {
           printf("int value is : %d.\n", valueArr->value.intValue);
           }
           printf("----------------------------basic info-------------------------------\n");
           */

        // write a int
        if (colDef->type == DATA_INT && valueArr->isChar == 1)
        {
            //printf("write a int\n");
            char nullBit = 1;
            memcpy(dataBuf, &nullBit, sizeof(char));
            dataBuf = dataBuf + sizeof(char);
            memcpy(dataBuf, &valueArr->value.intValue, sizeof(int));
            dataBuf = dataBuf + sizeof(int);
        }
        // write a vchar
        // Attention : we must record how much space this vchar use in fact
        else if (colDef->type == DATA_VCHAR && valueArr->isChar == 0)
        {
            //printf("write a vchar\n");
            // record how much space this vchar use in fact
            char nullBit = 1;
            memcpy(dataBuf, &nullBit, sizeof(char));
            dataBuf = dataBuf + sizeof(char);
            int vcharLen = strlen(valueArr->value.charValue);
            memcpy(dataBuf, &vcharLen, sizeof(int));
            dataBuf = dataBuf + sizeof(int);
            memcpy(dataBuf, &valueArr->value.charValue, colDef->size);
            dataBuf = dataBuf + colDef->size;
        }
        // write a char
        else if (colDef->type == DATA_CHAR && valueArr->isChar == 0)
        {
            //printf("write a char\n");
            char nullBit = 1;
            memcpy(dataBuf, &nullBit, sizeof(char));
            dataBuf = dataBuf + sizeof(char);
            memcpy(dataBuf, &valueArr->value.charValue, colDef->size);
            dataBuf = dataBuf + colDef->size;
        }
        // write a NULL
        else if (valueArr->isChar == 2)
        {
            char nullBit = 0;
            memcpy(dataBuf, &nullBit, sizeof(char));
            dataBuf = dataBuf + sizeof(char);
            if (colDef->type == DATA_VCHAR)
            {
                int len = 0;
                memcpy(dataBuf, &len, sizeof(int));
                dataBuf = dataBuf + sizeof(int);
            }
            char* pointer = malloc(colDef->size);
            memcpy(dataBuf, pointer, colDef->size);
            dataBuf = dataBuf + colDef->size;
            free(pointer);
        }
    }

    //printf("write finish!\n");    

    // update the slotCnt
    buf->pgheader.slotCnt = buf->pgheader.slotCnt + 1;
    // wirte to file
    DBPageRelease(fileid, newpageid, TRUE);
    DBDisposePage(fileid, newpageid);

    // update the definition file
    // in fact, only need to update the recordCount
    recordCount = recordCount + 1;
    //printf("recordCount is %d.\n", recordCount);
    fseek(fp, 0, SEEK_SET);
    fwrite(&recordCount, sizeof(unsigned long), 1, fp);
    fclose(fp);

    //free(buf);
    //free(dataBuf);
    free(tName);
    free(colDef);
    return 0;

}

int insertChaos(const char* tableName, colValue* valueArr, char** colNames)
{
    /*
    // first we need to adjust the order
    printf("insertChaos.\n\n");
    int i = 0;
    int k = 0;

    // get the file name
    char fileName[50];
    strcpy(fileName, tableName);
    col* colDef = malloc(sizeof(col));
    strcat(fileName, ".dbf");
    printf("filename is %s.\n", fileName);
    // end of file name
    FILE* fp;
    fp = fopen(fileName, "rb");
    if (fp == NULL)
    {
    printf("can not find file.\n");
    return;
    }

    // get the colCount(how many cols are defined in the table)
    fseek(fp, 4, 0);
    int colCount;
    fread(&colCount, sizeof(int), 1, fp);
    int* offsetArr = malloc(colCount * sizeof(int));
    // insert the recoreds
    for (i = 0; i < colCount; i++)    
    {
    fread(colDef, sizeof(col), 1, fp);
    printf("the col name is : %s.\n", colDef->name);
    for (k = 0;k < colCount;k++)
    {
    if (strcmp(colDef->name, colNames[k]) == 0)
    {
     *(offsetArr + i) = k;
     }
     }
     }
     */

    char fileName[50];
    strcpy(fileName, tableName);
    col* colDef = malloc(sizeof(col));
    strcat(fileName, ".dbf");

    FILE* fp;
    fp = fopen(fileName, "rb");
    if (fp == NULL)
    {
        printf("open table def file error in insertChaos.\n");
        return -1;
    }

    int colCount;
    fseek(fp, 4, 0);
    fread(&colCount, sizeof(int), 1, fp);
    int* offsetArr = malloc(colCount * sizeof(int));
    int i, k;
    for (i = 0; i < colCount; i++)
    {
        fread(colDef, sizeof(col), 1, fp);
        for (k = 0;k < colCount; k++)
        {
            if (strcmp(colDef->name, colNames[k]) == 0)
            {
                * (offsetArr + i) = k;
            }
        }
    }
    fclose(fp);

    colValue* newArr = malloc(colCount * sizeof(colValue));
    for (i = 0; i < colCount; i++)
    {
        memcpy(newArr + i, valueArr + *(offsetArr + i), sizeof(colValue));
    }


    /*
       for (i = 0;i < colCount; i++, newArr++)
       {
       if (newArr->isChar == 0)
       {
       printf("This is a char.\n");
       printf("%s\n", newArr->value.charValue);
       }
       else
       {
       printf("This is a int.\n");
       printf("%d\n", newArr->value.intValue);
       }
       }*/

    insertNormal(tableName, newArr);

    free(offsetArr);
    free(colDef);
    free(newArr);

    return 1;
}

